#ifndef __BASE_MINI_DUMP_H__
#define __BASE_MINI_DUMP_H__
#pragma once

#ifdef _WIN32

//使用: SetUnhandledExceptionFilter(UnhandledExceptionFilterEx);

#include <cstdio>
#include <Shlwapi.h>
#include <DbgHelp.h>

#pragma comment(lib, "ShLwApi.lib")
#pragma comment(lib, "DbgHelp.lib")

BOOL CALLBACK MiniDumpCallback(PVOID, const PMINIDUMP_CALLBACK_INPUT input, PMINIDUMP_CALLBACK_OUTPUT output)
{
	if (input == NULL || output == NULL)
		return FALSE;
	BOOL ret = FALSE;
	switch (input->CallbackType)
	{
	case IncludeModuleCallback:
	case IncludeThreadCallback:
	case ThreadCallback:
	case ThreadExCallback:
	{
		ret = TRUE;
	}
	break;
	case ModuleCallback:
	{
		if (!(output->ModuleWriteFlags & ModuleReferencedByMemory))
		{
			output->ModuleWriteFlags &= ModuleWriteModule;
		}
		ret = TRUE;
	}
	break;
	default:
		break;
	}
	return ret;
}

void WriteDump(EXCEPTION_POINTERS* exp, LPCSTR path)
{
	HANDLE hd = ::CreateFileA(path,
		GENERIC_WRITE | GENERIC_READ,
		FILE_SHARE_WRITE | FILE_SHARE_READ,
		NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	if (hd == INVALID_HANDLE_VALUE)
	{
		return;
	}
	MINIDUMP_EXCEPTION_INFORMATION mei;
	mei.ThreadId = ::GetCurrentThreadId();
	mei.ExceptionPointers = exp;
	mei.ClientPointers = NULL;

	MINIDUMP_CALLBACK_INFORMATION mci;
	mci.CallbackRoutine = (MINIDUMP_CALLBACK_ROUTINE)MiniDumpCallback;
	mci.CallbackParam = 0;

	MINIDUMP_TYPE mt = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory);
	MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hd, mt, &mei, NULL, &mci);
	::CloseHandle(hd);
}

LONG WINAPI UnhandledExceptionFilterEx(EXCEPTION_POINTERS* exp)
{
	SYSTEMTIME st;
	GetLocalTime(&st);
	char szfName[_MAX_FNAME] = { 0 };
	sprintf_s(szfName, "%04d%02d%02d_%02d%02d%02d.dmp", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);

	char szfPath[_MAX_PATH] = { 0 };
	GetModuleFileNameA(NULL, szfPath, sizeof(szfPath) - 1);
	(strrchr(szfPath, '\\'))[0] = 0;
	strcat_s(szfPath, "\\dumps");
	if (!PathFileExistsA(szfPath))
	{
		CreateDirectoryA(szfPath, NULL);
	}
	strcat_s(szfPath, "\\");
	strcat_s(szfPath, szfName);

	WriteDump(exp, szfPath);

	return EXCEPTION_EXECUTE_HANDLER;
}

#endif //_WIN32
#endif //__BASE_MINI_DUMP_H__